package black.market.weather;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.http.NameValuePair;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.content.ContentValues;
import android.content.Context;
import android.content.IntentFilter;
import android.content.res.Resources;
import black.market.location.LocationDAO;
import black.market.location.ReadLocation;
import black.market.main.BlackPublic;
import black.market.main.BlackPublic.Action;
import black.market.main.DownloadHtml;
import black.market.main.R;
import black.market.main.XpathParser;
import black.market.util.Log;

public class KmaInfoData {
	public static final String TAG = "ExampleWeatherData";
	private String KMA_DEFAULT_ADDRESS = "http://www.kma.go.kr";
	private String ENCODING = "utf-8";
	private Context mContext = null;
	private Resources mResources = null;
	private XPath xPath = null;
	private XPathFactory xPathFactory = XPathFactory.newInstance();;
	private DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
	private DocumentBuilder builder = null;
	private Document xPathDocument = null;
	private LocationDAO locationDAO = null;
	private KmaInfoDAO kmaInfoDAO = null;
	private ReadLocation readLocation = null;

	public KmaInfoData(Context context) {
		super();
		this.mContext = context;
		this.mResources = mContext.getResources();
		readLocation = new ReadLocation(mContext);
		locationDAO = new LocationDAO(mContext);
		kmaInfoDAO = new KmaInfoDAO(mContext);

		IntentFilter filter = new IntentFilter();
		filter.addAction(Action.KMA_DATA_INTERVAL3H.toString());
		filter.addAction(Action.LOCATION_CHANGED_ACTION.toString());
		filter.addAction(Action.GEOCODE_TO_ADDRESS.toString());
		// mContext.registerReceiver(receiver, filter);
	}

	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		// mContext.unregisterReceiver(receiver);
		super.finalize();
	}

	public void getKmaData_Interval_3H(Resources resources, String expr) {
		XpathParser parser = new XpathParser();
		try {
			String xmlMsg = openKmaDataXml(resources);
			String grid = parser.gridXpathParserCompile(xmlMsg, expr);
			DownloadHtml html = new DownloadHtml();
			Log.d(TAG, "Kma Request Address: " + KMA_DEFAULT_ADDRESS + grid);
			String res = html.httpGetTypeReturn(KMA_DEFAULT_ADDRESS + grid, new ArrayList<NameValuePair>());
			gridDataXmlToNodeList2(res);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (XPathExpressionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public String openKmaDataXml(Resources resources) throws IOException {
		InputStream is = resources.openRawResource(R.raw.kmadata);
		byte[] tmpByteArr = new byte[is.available()];
		int pos = 0;
		int size = 10;
		int tmp = 0;
		while ((size = is.read(tmpByteArr, pos, size)) > 0) {
			pos += size;
			tmp = tmpByteArr.length - pos;
			if (tmp < 10) {
				size = tmp;
			}
		}
		is.close();
		return new String(tmpByteArr, "utf-8");
	}

	public void gridDataXmlToNodeList2(String data) throws ParserConfigurationException, UnsupportedEncodingException, SAXException, IOException, XPathExpressionException {
		Log.d(TAG, "Stream data: " + data);
		String HEADER_EXPRESSION = "//header/*";
		factory.setIgnoringElementContentWhitespace(true);
		factory.setIgnoringComments(true);
		factory.setNamespaceAware(true);
		builder = factory.newDocumentBuilder();
		xPathDocument = builder.parse(new ByteArrayInputStream(data.getBytes(ENCODING)));
		xPath = xPathFactory.newXPath();
		XPathExpression h_expr = xPath.compile(HEADER_EXPRESSION);
		Object h_obj = h_expr.evaluate(xPathDocument, XPathConstants.NODESET);
		NodeList h_NodeList = (NodeList) h_obj;
		NodeList b_NodeList = xPathDocument.getElementsByTagName("data");
		BlackPublic.identifiesLog(TAG, "header leng: " + h_NodeList.getLength() + "body leng: " + b_NodeList.getLength());
		String time = gridHeaderInsertDatabase(h_NodeList);
		gridBodyInsertDatabase(b_NodeList, time);
	}

	public String gridHeaderInsertDatabase(NodeList list) {
		int len = list.getLength();
		boolean isChild = false;
		String time = null;
		ContentValues h_cv = new ContentValues();
		Log.d(TAG, "H len: " + len);
		if (len > 0) {
			mContext.getContentResolver().delete(WeatherContentProvider.HEADER_URI, null, null);
			for (int i = 0; i < len; i++) {
				isChild = list.item(i).hasChildNodes();
				if (isChild) {
					String nodeName = list.item(i).getNodeName();
					String nodeText = list.item(i).getTextContent();
					Log.d(TAG, "nodeName: " + nodeName);
					Log.d(TAG, "nodeText: " + nodeText);
					switch (Header.toHeader(nodeName)) {
					case TM:
						h_cv.put(WeatherContentProvider.WB_TIMEMAP, nodeText);
						time = nodeText;
						break;
					case TS:
						h_cv.put(WeatherContentProvider.WB_TIMESTEP, nodeText);
						break;
					case X:
						h_cv.put(WeatherContentProvider.WB_LATITUDE, nodeText);
						break;
					case Y:
						h_cv.put(WeatherContentProvider.WB_LONGITUDE, nodeText);
						mContext.getContentResolver().insert(WeatherContentProvider.HEADER_URI, h_cv);
						break;
					default:
						BlackPublic.warningLog(TAG, "not found case: " + Header.toHeader(nodeName));
						break;
					}

				}
			}
		} else {
			BlackPublic.errorLog(TAG, "Header is 0");
		}

		return time;
	}

	public void gridBodyInsertDatabase(NodeList list, String time) {
		int len = list.getLength();
		String nodeName = null;
		String nodeText = null;
		ContentValues b_cv = new ContentValues();
		Log.d(TAG, "B len: " + len);
		if (len > 0) {
			for (int i = 0; i < len; i++) {
				Node tmpNode = list.item(i);
				NodeList tmpChildList = tmpNode.getChildNodes();
				int tmpLen = tmpChildList.getLength();
				for (int j = 0; j < tmpLen; j++) {
					Node childNode = tmpChildList.item(j);
					b_cv.put(WeatherContentProvider.WB_TIMEMAP, time);
					if (childNode.getNodeType() == Node.ELEMENT_NODE) {
						boolean isUpdateHour = false;
						String[][] hoursArr = kmaInfoDAO.getHour_Id();
						String body_Id = null;
						nodeName = childNode.getNodeName();
						nodeText = childNode.getFirstChild().getNodeValue();
						Log.d(TAG, "ChildnodeName: " + nodeName);
						Log.d(TAG, "ChildnodeText: " + nodeText);
						switch (Body.toBody(nodeName)) {
						case DATA:
							b_cv.put(WeatherContentProvider.WB_DATATYPE, "기상청");
							break;

						case HOUR:
							for (int k = 0; k < hoursArr.length; k++) {
								if (nodeText.equals(hoursArr[k][1])) {
									isUpdateHour = true;
									body_Id = hoursArr[k][0];
								}
							}
							b_cv.put(WeatherContentProvider.WB_HOUR, nodeText);
							break;

						case DAY:
							b_cv.put(WeatherContentProvider.WB_DAY, nodeText);
							break;

						case TEMP:
							b_cv.put(WeatherContentProvider.WB_TEMP, nodeText);
							break;

						case TMX:
							b_cv.put(WeatherContentProvider.WB_TEMPMAX, nodeText);
							break;

						case TMN:
							b_cv.put(WeatherContentProvider.WB_TEMPMIN, nodeText);
							break;

						case SKY:
							b_cv.put(WeatherContentProvider.WB_SKY, nodeText);
							break;

						case PTY:
							b_cv.put(WeatherContentProvider.WB_PRECIPITATION, nodeText);
							break;

						case WFKOR:
							b_cv.put(WeatherContentProvider.WB_KOR_STATE, nodeText);
							break;
						case WFEN:
							b_cv.put(WeatherContentProvider.WB_EN_STATE, nodeText);
							break;
						case POP:
							b_cv.put(WeatherContentProvider.WB_POP, nodeText);
							break;
						case R12:
							b_cv.put(WeatherContentProvider.WB_RAIN12, nodeText);
							break;
						case S12:
							b_cv.put(WeatherContentProvider.WB_SNOW12, nodeText);
							break;
						case WS:
							b_cv.put(WeatherContentProvider.WB_WINDSPEED, nodeText);
							break;
						case WD:
							b_cv.put(WeatherContentProvider.WB_WINDDIRECTION, nodeText);
							break;
						case WDKOR:
							b_cv.put(WeatherContentProvider.WB_KOR_WINDDIRECTION, nodeText);
							break;
						case WDEN:
							b_cv.put(WeatherContentProvider.WB_EN_WINDDIRECTION, nodeText);
							break;
						case REH:
							b_cv.put(WeatherContentProvider.WB_REH, nodeText);
							Log.d(TAG, "nodeText1: " + nodeText);
							if (isUpdateHour) {
								String where = WeatherContentProvider.WB_BODY_ID + "=?";
								String[] selectionArgs = { body_Id };
								mContext.getContentResolver().update(WeatherContentProvider.BODY_URI, b_cv, where, selectionArgs);
								Log.d(TAG, "isUpdateHour: " + isUpdateHour + "-> update");
							} else {
								Log.d(TAG, "isUpdateHour: " + isUpdateHour + "-> insert");
								mContext.getContentResolver().insert(WeatherContentProvider.BODY_URI, b_cv);
							}
							break;
						default:
							BlackPublic.warningLog(TAG, "not found case: " + Body.toBody(nodeName));
							break;
						}
					}
				}
			}
		} else {
			BlackPublic.errorLog(TAG, "Body is 0");
		}

	}

	public enum Header {
		TM, TS, X, Y;

		public static Header toHeader(String str) {
			// TODO Auto-generated method stub
			return valueOf(str.toUpperCase());
		}
	}

	public enum Body {
		DATA, HOUR, DAY, TEMP, TMX, TMN, SKY, PTY, WFKOR, WFEN, POP, R12, S12, WS, WD, WDKOR, WDEN, REH, TM;

		public static Body toBody(String str) {
			return valueOf(str.toUpperCase());
		}
	}

}
